module fiona_objects_mod

  use fiona_common_mod
  use fiona_dataset_mod

  implicit none

  type(hash_table_type) datasets

  real(8) time_units_in_seconds
  character(30) :: time_units_str = 'N/A'
  character(30) :: start_time_str = 'N/A'

contains

  logical function fiona_has_dataset(dataset_name) result(res)

    character(*), intent(in)  :: dataset_name

    res = datasets%hashed(dataset_name)

  end function fiona_has_dataset

  logical function fiona_has_var(dataset_name, var_name) result(res)

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name

    type(dataset_type), pointer :: dataset
    integer ierr, varid

    dataset => get_dataset(dataset_name)

    if (dataset%is_group_root) then
      if (.not. dataset%is_open()) then
        ierr = NF90_OPEN(dataset%file_path, NF90_NOWRITE, dataset%id)
        call handle_error(ierr, 'Failed to open dataset ' // trim(dataset_name) // '!', __FILE__, __LINE__)
      end if
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      res = ierr == NF90_NOERR
    end if
#ifdef HAS_MPI
    if (dataset%group_mpi_comm /= MPI_COMM_NULL) then
      call MPI_BCAST(res, 1, MPI_LOGICAL, 0, dataset%group_mpi_comm, ierr)
    end if
#endif

  end function fiona_has_var

  function get_dataset(dataset_name) result(res)

    character(*), intent(in) :: dataset_name
    type(dataset_type), pointer :: res

    select type (value => datasets%value(dataset_name))
    type is (dataset_type)
      res => value
    class default
      call log_error('Failed to get dataset ' // trim(dataset_name) // '!', __FILE__, __LINE__)
    end select

  end function get_dataset

  subroutine fiona_set_dim(dataset_name, dim_name, span, cyclic, flip)

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: dim_name
    class(*), intent(in), optional :: span(2)
    logical, intent(in), optional :: cyclic
    logical, intent(in), optional :: flip

    type(dataset_type), pointer :: dataset => null()
    type(dim_type), pointer :: dim => null()

    dataset => get_dataset(dataset_name)
    dim => dataset%get_dim(dim_name)

    if (.not. associated(dim)) then
      call log_error('fiona_set_dim: Cannot find dimension "' // trim(dim_name) // '"!', __FILE__, __LINE__)
    end if

    if (present(span)) then
      select type (span)
      type is (integer)
        dim%span = span
      type is (real(4))
        dim%span = span
      type is (real(8))
        dim%span = span
      end select
      dim%length = dim%span(2) - dim%span(1)
    end if
    if (present(cyclic)) dim%cyclic = cyclic
    if (present(flip)) dim%flip = flip

    if (dim%flip) then
      dim%span = dim%span(2:1:-1)
      dim%length = dim%span(2) - dim%span(1)
    end if

  end subroutine fiona_set_dim

end module fiona_objects_mod
